<?php

namespace common\service;

use common\model\SaasEntityModel;
use common\model\PlanModel;
use common\model\SaasProjectModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use Throwable;

class PlanService
{
    use SingletonTrait;

    /**
     * 导入计划
     * @param $dataList
     * @param $tenantId
     * @return mixed
     * @throws Exception
     * @throws Throwable
     */
    public function import($dataList, $tenantId)
    {
        $projectList = model(SaasProjectModel::class)->where(['tenant_id' => $tenantId])->select();
        $projectList = array_column($projectList, null, 'name');
        $showStepCategoryList = teamones_request('teamones-saas', 'project/get_show_step_category_group', []);
        $showStepCategoryMap = array_column($showStepCategoryList['data'], null, 'name');
        $episodeList = model(SaasEntityModel::class)
            ->where([
                'project_id' => ['IN', array_column($projectList, 'id')],
                'module_id' => SaasModuleService::getInstance()->byCode('episode')['id'],
            ])
            ->field("id,name,code,project_id,concat(project_id, '#', code) unique_key")
            ->select();
        $episodeMap = array_column($episodeList, null, 'unique_key');

        $planCommonService = CommonService::instance('plan');
        $filter = [];
        $this->validateAndFormatData($dataList, $projectList, $episodeMap, $showStepCategoryMap, $filter);
        $oldPlanList = $this->getOldData($filter);
        $oldPlanList = array_column($oldPlanList, null, 'unique_key');

        // 组装更新和插入数据
        $insertList = [];
        $updateList = [];
        $insertMap = [];
        $insertLen = 0;
        $updateMap = [];
        $updateLen = 0;

        unset($data);
        foreach ($dataList as $data) {
            if ($data['flag'] === false) {
                continue;
            }
            $oldPlan = $oldPlanList[$data['unique_key']] ?? null;
            if (empty($oldPlan)) {
                // 新增
                // 后来的覆盖前面的
                $dealData = $planCommonService->dealCreateCustomField($data, 'plan');
                ksort($dealData);
                $dealData['created'] = time();
                $dealData['created_by'] = fill_created_by();
                $dealData['tenant_id'] = auto_fill_tenant_id();
                $dealData['step_category_ids'] = json_encode($dealData['step_category_ids']);
                if (!isset($insertMap[$data['unique_key']])) {
                    $insertList[] = $dealData;
                    $insertMap[$data['unique_key']] = $insertLen;
                    $insertLen += 1;
                } else {
                    $insertList[$insertMap[$data['unique_key']]] = $dealData;
                }
            } else {
                // 更新
                if ($oldPlan['start_time'] != $data['start_time'] || $oldPlan['end_time'] != $data['end_time']) {
                    if (!isset($updateMap[$data['unique_key']])) {
                        $updateList[] = [
                            'id' => $oldPlan['id'],
                            'start_time' => $data['start_time'],
                            'end_time' => $data['end_time'],
                            'updated' => time(),
                            'updated_by' => fill_created_by(),
                        ];
                        $updateMap[$data['unique_key']] = $updateLen;
                        $updateLen += 1;
                    } else {
                        $updateList[$updateMap[$data['unique_key']]] = [
                            'id' => $oldPlan['id'],
                            'start_time' => $data['start_time'],
                            'end_time' => $data['end_time'],
                            'updated' => time(),
                            'updated_by' => fill_created_by(),
                        ];
                    }
                }
            }
        }

        if (empty($insertList) && empty($updateList)) {
            return $dataList;
        }

        // 批量事务操作
        model(PlanModel::class)->startTrans();

        try {
            if (!empty($insertList)) {
                model(PlanModel::class)->addAll($insertList);
            }
            if (!empty($updateList)) {
                model(PlanModel::class)->saveAll($updateList);
            }
            model(PlanModel::class)->commit();
        } catch (Throwable $e) {
            model(PlanModel::class)->rollback();
            throw $e;
        }

        return $dataList;
    }

    /**
     * 验证并格式化数据
     * @param $dataList
     * @param array $projectList
     * @param array $episodeMap
     * @param array $showStepCategoryMap
     * @param $filter
     * @return void
     */
    private function validateAndFormatData(&$dataList, array $projectList, array $episodeMap, array $showStepCategoryMap, &$filter)
    {
        foreach ($dataList as &$data) {
            $data['flag'] = false;
            $data['start_time'] = strtotime($data['start_date']);
            $data['end_time'] = strtotime($data['end_date']);
            if ($data['end_time'] < $data['start_time']) {
                $data['err_msg'] = '计划时间有误';
                $data['err_code'] = ErrorCode::PLAN_DATE_INVALID;
                continue;
            }
            if (!isset($projectList[$data['project_name']])) {
                $data['err_msg'] = '项目找不到';
                $data['err_code'] = ErrorCode::PROJECT_NOT_FOUND;
                continue;
            }
            $data['project_id'] = $projectList[$data['project_name']]['id'];
            if (!isset($showStepCategoryMap[$data['step_category_name']])) {
                $data['err_msg'] = '环节找不到';
                $data['err_code'] = ErrorCode::SHOW_STEP_CATEGORY_NOT_FOUND;
                continue;
            }
            $data['step_category_ids'] = $showStepCategoryMap[$data['step_category_name']]['children_ids'];


            if (!isset($episodeMap[$data['project_id'] . '#' . $data['episode_code']])) {
                $data['err_msg'] = '剧集找不到';
                $data['err_code'] = ErrorCode::EPISODE_NOT_FOUND;
                continue;
            }
            $data['flag'] = true;
            $data['episode_id'] = $episodeMap[$data['project_id'] . '#' . $data['episode_code']]['id'];
            $filter[] = [
                'project_id' => $data['project_id'],
                'episode_id' => $data['episode_id'],
                'step_category_name' => $data['step_category_name'],
            ];
            $data['unique_key'] = sprintf("%d#%d#%s", $data['project_id'], $data['episode_id'], $data['step_category_name']);
        }
    }

    /**
     * 计划列表
     * @param $filter
     * @param array $page
     * @return array
     * @throws Exception
     */
    public function list($filter, array $page)
    {
        $res = [
            'total' => 0,
            'rows' => [],
        ];
        $res['total'] = model(PlanModel::class)->where($filter)->count();
        $res['rows'] = model(PlanModel::class)->where($filter)->page(...$page)->select();
        if (empty($res['rows'])) {
            return $res;
        }
        $projectIdList = [];
        $episodeIdList = [];
        foreach ($res['rows'] as $row) {
            $projectIdList[$row['project_id']] = $row['project_id'];
            $episodeIdList[$row['episode_id']] = $row['episode_id'];
        }
        $projectList = model(SaasProjectModel::class)->where(['id' => ['IN', implode(',', $projectIdList)]])->field('id,name')->select();
        $projectList = array_column($projectList, null, 'id');
        $episodeList = model(SaasEntityModel::class)->where(['id' => ['IN', implode(',', $episodeIdList)]])->field('id,name,code')->select();
        $episodeList = array_column($episodeList, null, 'id');
        foreach ($res['rows'] as &$row) {
            CommonService::instance('plan')->getFormatAttrData($row);
            $row['project'] = $projectList[$row['project_id']] ?? null;
            $row['episode'] = $episodeList[$row['episode_id']] ?? null;
        }
        return $res;
    }

    /**
     * 查询历史数据
     * @param array $filter
     * @return array|false|mixed|string
     */
    private function getOldData(array $filter)
    {
        if (empty($filter)) {
            return [];
        }
        if (count($filter) > 1) {
            $filter['_logic'] = 'OR';
            $filter = [$filter];
        } else {
            $filter = $filter[0];
        }
        // 查询历史计划
        return model(PlanModel::class)->where($filter)->field("id,start_time,end_time,concat(project_id,'#',episode_id,'#',step_category_name) unique_key")->select();
    }
}
